package com.xlh.virtualization.controller;

import com.xlh.common.Result;
import com.xlh.security.UserInfoHolder;
import com.xlh.virtualization.domain.ContainerContext;
import com.xlh.virtualization.domain.ExperimentContainer;
import com.xlh.virtualization.domain.ExperimentContext;
import com.xlh.virtualization.po.ImageAllocationImageUpdatePO;
import com.xlh.virtualization.po.ImageAllocationUpdatePO;
import com.xlh.virtualization.service.ContainerService;
import com.xlh.virtualization.service.ExperimentService;
import com.xlh.virtualization.service.ImageAllocationService;
import com.xlh.virtualization.vo.ImageAllocationContainerVO;
import com.xlh.virtualization.vo.ImageAllocationVO;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static com.xlh.virtualization.constant.ContainerRoleEnum.SLAVE;

/**
 * @author cheer
 */
public abstract class BaseImageAllocationController {

    protected UserInfoHolder userInfoHolder;

    protected ImageAllocationService imageAllocationService;

    protected ExperimentService experimentService;

    protected ContainerService containerService;

    public Result<ImageAllocationVO> getImageAllocation(Long contextId) {
        ImageAllocationVO imageAllocationVO = imageAllocationService.getImageAllocation(getImageAllocationContextType(),
                contextId);
        return Result.success(imageAllocationVO);
    }

    public Result updateImageAllocation(Long contextId, ImageAllocationUpdatePO imageAllocationUpdatePO) {
        imageAllocationService.updateImageAllocation(getImageAllocationContextType(), contextId, imageAllocationUpdatePO);
        return Result.success();
    }

    public Result deleteImageAllocation(Long contextId) {
        imageAllocationService.deleteImageAllocation(getImageAllocationContextType(), contextId);
        return Result.success();
    }

    public Result<List<ImageAllocationContainerVO>> enterExperiment(Long contextId) {
        // 获取实验环境的类型和资源id
        ContainerContext containerContext = getContainerContext(userInfoHolder.getUserId(), contextId);

        ExperimentContext experimentContext = getExperimentContext(userInfoHolder.getUserId(), contextId);

        // 获取实验容器
        List<ExperimentContainer> experimentContainers = getExperimentContainers(containerContext, experimentContext);

        containerService.deleteExtraContainerByContext(containerContext,
                experimentContainers.stream().map(ExperimentContainer::getContainerId).collect(Collectors.toList()));

        return buildImageAllocationContainerVO(experimentContainers);
    }

    public Result<List<ImageAllocationContainerVO>> initExperiment(Long contextId) {
        // 获取实验环境的类型和资源id
        ContainerContext containerContext = getContainerContext(userInfoHolder.getUserId(), contextId);

        ExperimentContext experimentContext = getExperimentContext(userInfoHolder.getUserId(), contextId);

        containerService.deleteContainerByContext(containerContext);

        List<ExperimentContainer> experimentContainers = getExperimentContainers(containerContext, experimentContext);

        return buildImageAllocationContainerVO(experimentContainers);
    }

    public Result updateImage(Long contextId, ImageAllocationImageUpdatePO imageAllocationImageUpdatePO) {
        imageAllocationService.updateImage(getImageAllocationContextType(), contextId, imageAllocationImageUpdatePO);
        return Result.success();
    }

    private List<ExperimentContainer> getExperimentContainers(ContainerContext containerContext, ExperimentContext experimentContext) {
        try {
            return experimentService.getExperiment(containerContext, experimentContext, null);
        } catch (Exception e) {
            containerService.stopContainerByContext(containerContext);
            throw e;
        }
    }

    private Result<List<ImageAllocationContainerVO>> buildImageAllocationContainerVO(List<ExperimentContainer> experimentContainers) {
        List<ImageAllocationContainerVO> imageAllocationContainerVOS = new ArrayList<>();
        for (ExperimentContainer experimentContainer : experimentContainers) {
            ImageAllocationContainerVO imageAllocationContainerVO = ImageAllocationContainerVO.builder()
                    .containerId(experimentContainer.getContainerId())
                    .containerRole(SLAVE == experimentContainer.getContainerRole() ?
                            experimentContainer.getContainerRole().getMessage() + experimentContainer.getRoleNumber() :
                            experimentContainer.getContainerRole().getMessage())
                    .imageId(experimentContainer.getImageId())
                    .desktopUrl(experimentContainer.getDesktopUrl())
                    .fullScreen(experimentContainer.getFullScreen())
                    .build();
            imageAllocationContainerVOS.add(imageAllocationContainerVO);
        }
        return Result.success(imageAllocationContainerVOS);
    }

    protected abstract ContainerContext getContainerContext(Long userId, Long contextId);

    protected abstract ExperimentContext getExperimentContext(Long userId, Long contextId);

    protected abstract Integer getImageAllocationContextType();
}
